use super::driver::{ctrl, motor};
use crate::{cmd::drop, error::AppErr, task::handler_task::Response};
use proto_bytes::message::ReqRef;

pub fn on_simple_req(req: ReqRef) -> Result<Response, AppErr> {
    let cmd = req.cmd();

    match cmd {
        drop::LED => req.parse().ok_or(AppErr::Parse).and_then(|req| on_led(req)),

        _ => Err(AppErr::InvalidCmd),
    }
}

pub fn on_request(req: ReqRef) -> Result<Response, AppErr> {
    let cmd = req.cmd();

    match cmd {
        drop::DROP_CUP => req
            .parse()
            .ok_or(AppErr::Parse)
            .and_then(|req| on_drop_cup(req)),

        drop::FILM_RESET => on_film_reset(),

        drop::ROBOT_RESET => on_robot_reset(),

        drop::CUT_FILM => req
            .parse()
            .ok_or(AppErr::Parse)
            .and_then(|req| on_cut_film(req)),

        drop::FILM => on_film(),

        _ => Err(AppErr::InvalidCmd),
    }
}

fn on_film() -> Result<Response, AppErr> {
    motor::film()?;
    Ok(Response::Empty(()))
}

fn on_cut_film(ctrl: u8) -> Result<Response, AppErr> {
    match ctrl {
        0 => motor::cut_film_top()?,
        1 => motor::cut_film_down()?,
        _ => return Err(AppErr::Invalid),
    };
    Ok(Response::Empty(()))
}

fn on_robot_reset() -> Result<Response, AppErr> {
    ctrl::robot_power_restart();
    Ok(Response::Empty(()))
}

fn on_film_reset() -> Result<Response, AppErr> {
    ctrl::film_power_restart();
    Ok(Response::Empty(()))
}

fn on_led((id, ctrl): (u8, u8)) -> Result<Response, AppErr> {
    let v = ((id as u16) << 8) | (ctrl as u16);
    match v {
        0x0100 => ctrl::light_led_open(),
        0x0101 => ctrl::light_led_close(),
        0x0200 => ctrl::fan_open(),
        0x0201 => ctrl::fan_close(),
        _ => return Err(AppErr::Invalid),
    }
    Ok(Response::Empty(()))
}

fn on_drop_cup(id: u8) -> Result<Response, AppErr> {
    match id {
        1 => ctrl::drop1_ctrl()?,
        2 => ctrl::drop2_ctrl()?,
        3 => ctrl::drop3_ctrl()?,
        _ => return Err(AppErr::Invalid),
    };
    Ok(Response::Empty(()))
}
